use aead::{generic_array::GenericArray, KeyInit};
use aes_gcm::Aes256Gcm;
use crypto::aead::Aead;
use sha2::{Digest, Sha256};

pub fn sha_256_ecb_bytes(text: &str) -> [u8; 32] {
    let text_data = text.as_bytes();
    let mut hasher = Sha256::new();

    hasher.update(text_data);
    hasher.finalize().into()
}

pub fn aes_encrypt_hex(text: &str, key: &str, nonce: &str) -> anyhow::Result<String> {
    let key = sha_256_ecb_bytes(key);

    let cipher = Aes256Gcm::new((&key).into());

    let nonce_data = padding_nonce(nonce);
    let nonce = Into::<GenericArray<u8, _>>::into(nonce_data);

    let encrypted = cipher.encrypt(&nonce, text.as_bytes())?;
    let encrypted_str = hex::encode(encrypted);

    Ok(encrypted_str)
}

pub fn aes_decrypt_hex(cipher_hex_text: &str, key: &str, nonce: &str) -> anyhow::Result<String> {
    let key = sha_256_ecb_bytes(key);

    let cipher = Aes256Gcm::new((&key).into());

    let nonce_data = padding_nonce(nonce);
    let nonce = Into::<GenericArray<u8, _>>::into(nonce_data);

    let cipher_bytes = hex::decode(cipher_hex_text)?;

    let decrypt = cipher.decrypt(&nonce, cipher_bytes.as_slice())?;

    let decrypt_str = String::from_utf8(decrypt)?;

    Ok(decrypt_str)
}

fn padding_nonce(nonce: &str) -> [u8; 12] {
    let mut nonce_bytes = [1u8; 12];

    let _nonce_bytes = nonce.as_bytes();
    let len = if _nonce_bytes.len() < nonce_bytes.len() {
        _nonce_bytes.len()
    } else {
        nonce_bytes.len()
    };

    for i in 0..len {
        nonce_bytes[i] = _nonce_bytes[i];
    }
    nonce_bytes
}

#[cfg(test)]
mod tests {
    use crate::crypto::{aes_decrypt_hex, padding_nonce, sha_256_ecb_bytes};

    use super::aes_encrypt_hex;

    #[test]
    fn test_sha_256_ecb_bytes() {
        let text = "hello world";
        let hash = sha_256_ecb_bytes(text);
        println!("hash: {:?}", &hash);
    }

    #[test]
    fn test_padding_nonce() {
        println!("nonce={:?}", padding_nonce("hello"));
        println!(
            "nonce={:?}",
            padding_nonce("hellohellohellohellohellohellohellohellohellohellohello")
        );
        println!("nonce={:?}", padding_nonce("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello"));
    }

    #[test]
    fn test_aes_encrypt_hex() {
        let text = "hello world";
        let key = "1234567890123456";
        let nonce = "1234567890123456";

        let encrypted = aes_encrypt_hex(text, key, nonce).unwrap();
        println!("encrypted: {}", encrypted);
    }

    #[test]
    fn test_aes_decrypt_hex() {
        let hex_text = "1be8235f86704e4f4546f7871713ea8cfab2222415119b7b6bae6f";
        let key = "1234567890123456";
        let nonce = "1234567890123456";

        let decrypt = aes_decrypt_hex(hex_text, key, nonce).unwrap();
        println!("decrypt: {}", decrypt);
    }
}
